package com.four.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.four.common.utils.PageUtils;
import com.four.common.utils.R;
import com.four.common.vo.CommodityTo;
import com.four.common.vo.ShoppingVo;
import com.four.common.vo.UserTo;
import com.four.seckill.feign.ShoppingFeign;
import com.four.seckill.entity.CommodityEntity;
import com.four.seckill.mapper.CommodityMapper;
import com.four.seckill.service.CommodityService;
import com.four.seckill.vo.CommodityVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author: hxw
 * @Date: 2022/01/06/11:31
 * @Description
 */
@Service
public class CommodityServiceImpl implements CommodityService {
    @Autowired
    private CommodityMapper commodityMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ShoppingFeign shoppingFeign;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 查询列表为设置
     * @param page
     * @param limit
     * @return
     */
    @Override
    public PageUtils getList(Integer page, Integer limit) {
        String s = redisTemplate.opsForValue().get("four:seckil:commodity:list");
        //查询状态为1的
        List<CommodityEntity> list = null;
        if (s==null) {
            List<CommodityEntity> list1 = commodityMapper.getList();
            list = list1.stream().filter(filter ->{
                //过滤状态为1的
                return filter.getComSeckStatus()==0;
            }).map(item ->{
                return item;
            }).collect(Collectors.toList());
            redisTemplate.opsForValue().set("four:seckil:commodity:list", JSON.toJSONString(list),1, TimeUnit.DAYS);
        }else {
            list = JSON.parseObject(s,new TypeReference<List<CommodityEntity>>(){});
        }
        return pageList(list,page,limit);
    }

    /**
     * 进行分页
     * @param list
     * @param page
     * @param limit
     * @return
     */
    private PageUtils pageList(List<CommodityEntity> list, Integer page, Integer limit) {
        //找到并提取响应的页面的数据
        List<CommodityEntity> commodityEntities = new ArrayList<>();
        //总数
        Integer sum = 0;
        //计算上页的最后一条
        Integer preObj = page - 1 != 0 ? page * limit - 1: page - 1;
        //计算这页的结尾条
        Integer nextObj = page * limit;
        for (CommodityEntity commodityEntity : list) {
            //循环一次数量加1
            sum++;
            if (sum>preObj && sum<=nextObj) {
                commodityEntities.add(commodityEntity);
            }
        }
        return new PageUtils(commodityEntities,list.size(),page,limit);
    }

    /**
     * 修改成秒杀的商品
     * @param commodityEntity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public R saveUpdCommodity(List<CommodityEntity> commodityEntity) {

        for (CommodityEntity entity : commodityEntity) {
            entity.setComSeckStatus(1);
            commodityMapper.saveUpdCommodity(entity);
        }
        //修改成秒杀商品时存储的redis
        redisTemplate.delete("four:seckil:commodity:list");
        return R.ok();
    }

    /**
     * 删除缓存中秒杀设置的商品
     * @param id
     * @return
     */
    @Override
    public R deleteCommodityRedis(Integer id) {
        String s = redisTemplate.opsForValue().get("four:seckil:commodity:list");
        if (s!=null) {
            List<CommodityEntity> commodityEntity = JSON.parseObject(s, new TypeReference<List<CommodityEntity>>() {
            });
            List<CommodityEntity> commodityEntities = new ArrayList<>();
            for (CommodityEntity record : commodityEntity) {
                if (!record.getComId().equals(id)){
                    commodityEntities.add(record);
                }
            }
            redisTemplate.opsForValue().set("four:seckil:commodity:list", JSON.toJSONString(commodityEntities),1, TimeUnit.DAYS);
            return R.ok();
        }
        return R.error(500,"数据已经过期");
    }


    /**
     * 商品分页模糊查
     * @param page
     * @param size
     * @param vo
     * @return
     */
    @Override
    public IPage<CommodityEntity> commodityList(Integer page, Integer size, CommodityVo vo, Integer catId) {
        Page<CommodityEntity> commodityPage=new Page<>(page,size);
        return commodityMapper.commodityList(commodityPage,vo,catId);
    }

    /**
     * 添加商品
     * @param commodity
     */
    @Override
    public void addCommdity(CommodityEntity commodity) {
        commodity.setSeckStartTime(new Date());
        commodityMapper.addCommdity(commodity);
    }

    /**
     * 根据id删除商品
     * @param comId
     */
    @Override
    public void deleteById(Integer comId) {
        commodityMapper.deleteById(comId);
    }

    /**
     * 根据id查询商品
     * @param comId
     * @return
     */
    @Override
    public CommodityEntity getCommodityById(Integer comId) {
        return commodityMapper.getCommodityById(comId);
    }

    /**
     * 根据id修改商品数据  状态为0
     * @param commodity
     * @return
     */
    @Override
    public R updateCommodityById(CommodityEntity commodity) {
        CommodityEntity commodityById = commodityMapper.getCommodityById(commodity.getComId());
        if (commodityById==null) {
            return R.error(500,"该商品不存在");
        }
        Integer status = 0;
        if (!commodityById.getComSeckStatus().equals(status)){
            return R.error(500,"该商品不存在");
        }
        commodityMapper.updateCommodityById(commodity);
        return R.ok();
    }

    /**
     * 查看详情
     * @param comId
     * @return
     */
    @Override
    public R commoditySeckill(Integer comId) {
        CommodityEntity commodityById = commodityMapper.getCommodityById(comId);
        Date startTime = new Date();
        if (startTime.before(commodityById.getSeckStartTime())) {
            return R.error(500,"该活动并未开启");
        }
        return R.ok().put("data",commodityById);
    }

    /**
     * 秒杀
     * @param comId
     * @param userToken
     * @param token
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public R seckillStatus(Integer comId, String userToken, String token) {
        //判断是否已经提交过一次，不能重复提交
        String seckillShop = redisTemplate.opsForValue().get(token);
        if (seckillShop==null) {
            return R.error(500,"您已经付过下过订单了，请稍后重试");
        }
        redisTemplate.delete(token);
        //查询用户是否登录
        String s = redisTemplate.opsForValue().get(userToken);
        if (s==null) {
            return R.error(500,"用户未登录");
        }
        UserTo userTo = JSON.parseObject(s, new TypeReference<UserTo>() {
        });
        //查询该商品是否存在
        BoundHashOperations<String, String, String> map = redisTemplate.boundHashOps("four:seckill:list:seckStatus:1:");
        CommodityEntity commodityById = null;
        List<String> values = map.values();
        if (!CollectionUtils.isEmpty(values)) {
            for (String value : values) {
                commodityById = JSON.parseObject(value,new TypeReference<CommodityEntity>(){});
                if (commodityById.getComId().equals(comId)) {
                    break;
                }
            }
        }
        if (commodityById==null) {
            return R.error(200,"该商品不存在或者已被秒杀");
        }
        Integer status = 1;
        if (!status.equals(commodityById.getComSeckStatus())) {
            return R.error(500,"该商品不存在或者已被秒杀");
        }
        //商品秒杀的时间是否结束
        Date date = new Date();
        if (!date.after(commodityById.getSeckEndTime())) {
            return R.error(200,"该商品已结束砍价");
        }
        ShoppingVo shoppingVo = ShoppingVo.shoppingVo();
        //订单编号
        shoppingVo.setOrderId("60093" + UUID.randomUUID());
        //用户编号
        shoppingVo.setUserId(userTo.getUserId());
        //用户名
        shoppingVo.setUserName(userTo.getUserName());
        //商品编号
        shoppingVo.setComId(commodityById.getComId());
        //总金额
        shoppingVo.setOrSum(commodityById.getComPrice());
        shoppingVo.setOrPrice(commodityById.getComPrice());
        //下单时间
        shoppingVo.setOrCreateTimem(new Date());
        //订单状态
        shoppingVo.setOrStatus(0);
        //添加订单
        R r = shoppingFeign.addShopping(shoppingVo);
        String code = String.valueOf(r.get("code"));
        String stat = "0";
        if (code.equals(stat)){
            return r;
        }
        return R.error(500,"购买失败");
    }

    /**
     * 开启秒杀
     * @return
     */
    @Override
    public R seckillList() {
        List<CommodityEntity> list = commodityMapper.getList();
        BoundHashOperations<String, String, String> map = redisTemplate.boundHashOps("four:seckill:list:seckStatus:1:");
        Date date = new Date();
        for (CommodityEntity commodityEntity : list) {
            //过滤状态为0的商品，留下与秒杀合格的商品
            if (commodityEntity.getComSeckStatus()==1 && date.after(commodityEntity.getSeckEndTime()) && date.after(commodityEntity.getSeckStartTime())){
                map.put(commodityEntity.getComId().toString(),JSON.toJSONString(commodityEntity));
            }
        }
        return R.ok("秒杀商品开启成功");
    }

    /**
     * feign调用根据编号查询商品的详情
     * @param commId
     * @return
     */
    @Override
    public CommodityTo getByCommId(Integer commId) {

        return commodityMapper.getByComId(commId);
    }

    /**
     * 修改状态为已收货
     * @param byCommId
     * @return
     */
    @Override
    public R updateByStatus(CommodityTo byCommId) {
        CommodityEntity commodityEntity = CommodityEntity.commodityEntity();
        BeanUtils.copyProperties(commodityEntity,byCommId);
        commodityMapper.updateByStatus(commodityEntity);
        return R.ok();
    }

    /**
     * 接口进行防幂等
     * @param comId
     * @param userToken
     * @return
     */
    @Override
    public String tokenKey(Integer comId, String userToken) {
        long timestamp = UUID.randomUUID().timestamp();
        redisTemplate.opsForValue().set(timestamp+"",userToken+comId);
        return timestamp + "";
    }
}
